#include "comm/znx_string.h"
#include "comm/znx_random.h"

void test_str()
{
    znx_str_t str = ZNX_STRING("aaaa");
    if (str.len != sizeof("aaaa") - 1 ||
        znx_strncmp(str.data, "aaaa", str.len) != 0) {
        DD_FATAL("unexcept result");
    }

    znx_str_t str1 = ZNX_NULL_STRING;
    if (str1.len != 0 || str1.data != NULL) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "bbbb");
    if (str.len != sizeof("bbbb") - 1 ||
        znx_strncmp(str.data, "bbbb", str.len) != 0) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET_NULL(&str);
    if (str.len != 0 || str.data != NULL) {
        DD_FATAL("unexcept result");
    }

    u_char str_a[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaa";
    u_char str_b[64];
    znx_memcpy(str_b, str_a, sizeof(str_a));
    if (znx_strncmp(str_b, str_a, sizeof(str_a))) {
        DD_FATAL("unexcept result");
    }

    u_char buf[64];
    ZNX_STR_SET(&str, "abcdefghijklmnopqrst");
    znx_str_to_cstr(&str, buf, sizeof(buf));
    if (znx_strlen(buf) != str.len || 
        znx_strncmp(buf, str.data, str.len) != 0) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "aaaa");
    ZNX_STR_SET(&str1, "aaaa");
    if (znx_str_cmp(&str, &str1) != 0) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "aaaa");
    ZNX_STR_SET(&str1, "AAAA");
    if (znx_str_cmp(&str, &str1) != 1) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "AAAA");
    ZNX_STR_SET(&str1, "aaaa");
    if (znx_str_cmp(&str, &str1) != -1) {
        DD_FATAL("unexcept result");
    }

    if (znx_str_case_cmp(&str, &str1) != 0) {
        DD_FATAL("unexcept result");
    }

    int64_t res;

    ZNX_STR_SET(&str, "+123");
    if (!znx_str_to_int64(&str, &res) || res != 123) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "-123");
    if (!znx_str_to_int64(&str, &res) || res != -123) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "123");
    if (!znx_str_to_int64(&str, &res) || res != 123) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "123.");
    if (znx_str_to_int64(&str, &res)) {
        DD_FATAL("unexcept result");
    }
}


void test_znx_str_to_double()
{
    double res;

    znx_str_t str;

    ZNX_STR_SET(&str, "+123");
    if (!znx_str_to_double(&str, &res) || res > 123 || res < 123) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "-123");
    if (!znx_str_to_double(&str, &res) || res > -123 || res < -123) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "123");
    if (!znx_str_to_double(&str, &res) || res > 123 || res < 123) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "+123.123");
    if (!znx_str_to_double(&str, &res) || res > 123.123 || res < 123.123) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "-123.123");
    if (!znx_str_to_double(&str, &res) || res > -123.123 || res < -123.123) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "123.123");
    if (!znx_str_to_double(&str, &res) || res > 123.123 || res < 123.123) {
        DD_FATAL("unexcept result");
    }

#if 0
    ZNX_STR_SET(&str, "-123.123e+12");
    if (!znx_str_to_double(&str, &res) || res > -123.123 * pow10(12) || res < -123.123 * pow10(12)) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "123.123e+12");
    if (!znx_str_to_double(&str, &res) || res > 123.123 * pow10(12) || res < 123.123 * pow10(12)) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "+123.123e12");
    if (!znx_str_to_double(&str, &res) || res > 123.123 * pow10(12) || res < 123.123 * pow10(12)) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "-123.123e12");
    if (!znx_str_to_double(&str, &res) || res > -123.123 * pow10(12) || res < -123.123 * pow10(12)) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "123.123e12");
    if (!znx_str_to_double(&str, &res) || res > 123.123 * pow10(12) || res < 123.123 * pow10(12)) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "+123.123e-12");
    if (!znx_str_to_double(&str, &res) || res > 123.123 / pow10(12) || res < 123.123 / pow10(12)) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "-123.123e-12");
    if (!znx_str_to_double(&str, &res) || res > -123.123 / pow10(12) || res < -123.123 / pow10(12)) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "123.123e-12");
    if (!znx_str_to_double(&str, &res) || res > 123.123 / pow10(12) || res < 123.123 / pow10(12)) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "+123e12");
    if (!znx_str_to_double(&str, &res) || res > 123 * pow10(12) || res < 123 * pow10(12)) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "-123e+12");
    if (!znx_str_to_double(&str, &res) || res > -123 * pow10(12) || res < -123 * pow10(12)) {
        DD_FATAL("unexcept result");
    }

    ZNX_STR_SET(&str, "123e-12");
    if (!znx_str_to_double(&str, &res) || res > 123 / pow10(12) || res < 123 / pow10(12)) {
        DD_FATAL("unexcept result");
    }
#endif

}


void test_parse_size()
{
    int64_t res;

    if (!znx_parse_size((u_char *)"1024", &res) ||
        res != 1024) {
        DD_FATAL("except 1024, but got other");
    }

    if (!znx_parse_size((u_char *)"1K", &res) ||
        res != 1024) {
        DD_FATAL("except 1024, but got other");
    }

    if (!znx_parse_size((u_char *)"1k", &res) ||
        res != 1024) {
        DD_FATAL("except 1024, but got other");
    }

    if (!znx_parse_size((u_char *)"1M", &res) ||
        res != 1024 * 1024) {
        DD_FATAL("except 1024 * 1024, but got other");
    }

    if (!znx_parse_size((u_char *)"1m", &res) ||
        res != 1024 * 1024) {
        DD_FATAL("except 1024 * 1024, but got other");
    }

    if (!znx_parse_size((u_char *)"1G", &res) ||
        res != 1024 * 1024 * 1024) {
        DD_FATAL("except 1024 * 1024 * 1024, but got other");
    }

    if (!znx_parse_size((u_char *)"1g", &res) ||
        res != 1024 * 1024 * 1024) {
        DD_FATAL("except 1024 * 1024 * 1024, but got other");
    }

    if (!znx_parse_size((u_char *)"1T", &res) ||
        res != (int64_t)1024 * 1024 * 1024 * 1024) {
        DD_FATAL("except 1024 * 1024 * 1024, but got other");
    }

    if (!znx_parse_size((u_char *)"1t", &res) ||
        res != (int64_t)1024 * 1024 * 1024 * 1024) {
        DD_FATAL("except 1024 * 1024 * 1024, but got other");
    }

    if (znx_parse_size((u_char *)"1x", &res)) {
        DD_FATAL("except false but got true");
    }

    if (znx_parse_size((u_char *)"1xx", &res)) {
        DD_FATAL("except false but got true");
    }
}


static int int_sort(const void *a, const void *b)
{
    int *ai = (int *)a;
    int *bi = (int *)b;

    if (*ai == *bi) {
        return 0;
    }

    return *ai > *bi ? 1 : -1;
}


void test_sort()
{
    int *arr = malloc(sizeof(int) * 100);
    for (int i = 0; i < 100; i++) {
        arr[i] = (int)(znx_random_n(1000));
    }

    for (int i = 0; i < 100; i++) {
        printf("%d ", arr[i]);
    }

    printf("\n");

    znx_qsort(arr, 100, sizeof(int), int_sort);


    for (int i = 0; i < 100; i++) {
        printf("%d ", arr[i]);
    }

    printf("\n");

    free(arr);
}


void test_path()
{
    assert(strcmp(znx_path_base("/aaa/bbbb/ccc/dddd/"), "") == 0);
    assert(strcmp(znx_path_base("/aaa/bbbb/ccc"), "ccc") == 0);
    assert(strcmp(znx_path_base("/aaa/bbbb"), "bbbb") == 0);
    assert(strcmp(znx_path_base("/1.txt"), "1.txt") == 0);
    assert(strcmp(znx_path_base(""), "") == 0);
}


void test_znx_str_cmp()
{
    znx_str_t str1 = ZNX_STRING("test");
    znx_str_t str2 = ZNX_STRING("test_a");
    znx_str_t str3 = ZNX_STRING("test_b");
    znx_str_t str4 = ZNX_STRING("test_a_a");
    znx_str_t str5 = ZNX_STRING("test_a_b");

    znx_str_t str6 = ZNX_STRING("TEST");
    znx_str_t str7 = ZNX_STRING("test_A");
    znx_str_t str8 = ZNX_STRING("test_B");
    znx_str_t str9 = ZNX_STRING("test_A_a");

    assert(znx_str_cmp(&str1, &str1) == 0);
    assert(znx_str_cmp(&str1, &str2) == -1);
    assert(znx_str_cmp(&str2, &str1) == 1);
    assert(znx_str_cmp(&str4, &str5) == -1);
    assert(znx_str_cmp(&str2, &str3) == -1);

    assert(znx_str_cmp_ext(&str1, "test") == 0);
    assert(znx_str_cmp_ext(&str2, "test") == 1);
    assert(znx_str_cmp_ext(&str1, "test_a") == -1);
    assert(znx_str_cmp_ext(&str2, "test_b") == -1);

    assert(znx_str_case_cmp(&str1, &str6) == 0);
    assert(znx_str_case_cmp(&str2, &str7) == 0);
    assert(znx_str_case_cmp(&str3, &str8) == 0);
    assert(znx_str_case_cmp(&str4, &str9) == 0);
    assert(znx_str_case_cmp(&str1, &str7) == -1);
    assert(znx_str_case_cmp(&str7, &str1) == 1);

    assert(znx_str_case_cmp_ext(&str1, "TEST") == 0);
    assert(znx_str_case_cmp_ext(&str2, "test_A") == 0);
    assert(znx_str_case_cmp_ext(&str3, "test_B") == 0);
    assert(znx_str_case_cmp_ext(&str4, "test_A_a") == 0);
    assert(znx_str_case_cmp_ext(&str1, "test_A") == -1);
    assert(znx_str_case_cmp_ext(&str7, "test") == 1);

}


void test_znx_sprintf()
{
    u_char      buf[1024];
    znx_str_t   str = ZNX_STRING("test");

    // out of bounds inspection
    u_char      tmp[2048];
    for (int i = 0; i < 2047; i++) {
        tmp[i] = 'a' + (u_char)(i % 10);
    }
    tmp[2047] = '\0';

    long n = 0;
    n = znx_snprintf(buf, 1024,
        "%2O %2O %2T %2z %2d %2l %2i %2D %2L %2.2f %p %V %s %s",
        1, 1111111, 1111111, 1111111, 1111111, 1111111, 1111111, 1111111, 1111111,
        12345.12345, (void *)(-1), &str, "1111111", tmp) - buf;
    DD("%ld", n);

    n = znx_snprintf_endof(buf, 1024, "%d %s %l", 100, "aaaa", 123);
    DD("%ld, %s", n, buf);
}


int main()
{
    test_str();
    test_znx_str_to_double();
    test_parse_size();
    test_path();
    test_sort();
    test_znx_str_cmp();
    test_znx_sprintf();

    return 0;
}